package run.iget.framework.common.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import lombok.extern.slf4j.Slf4j;
import run.iget.framework.common.bean.ExcelExportSet;

import javax.servlet.http.HttpServletResponse;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static cn.hutool.core.date.DatePattern.PURE_DATETIME_FORMAT;

/**
 * 代码千万行，注释第一行，注释不规范，迭代两行泪
 * ---------------类描述-----------------
 * 表格导出工具类
 * ---------------类描述-----------------
 *
 * @author 大周
 * @date 2023/8/23 21:22
 */
@Slf4j
public class ExcelUtils extends ExcelUtil {

    private final static String DEFAULT_SUFFIX = ".xlsx";

    /**
     * 文件导出下载到浏览器客户端，文件名称为uuid
     *
     * @param response 输出流
     * @param data     需要导出的数据集合
     */
    public static void export(HttpServletResponse response, List data) {
        export(response, genFileNameByDate(), data, null);
    }

    /**
     * 文件导出下载到浏览器客户端
     *
     * @param response 输出流
     * @param fileName 下载到的文件名称
     * @param data     需要导出的数据集合
     */
    public static void export(HttpServletResponse response, String fileName, List data) {
        export(response, fileName, data, null);
    }

    /**
     * 文件导出下载到浏览器客户端
     *
     * @param response       输出流
     * @param data           需要导出的数据集合, 如果为空，则下载到空表格
     * @param excelExportSet 表头列名映射
     */
    public static void export(HttpServletResponse response, List data, ExcelExportSet excelExportSet) {
        export(response, genFileNameByDate(), data, excelExportSet);
    }

    /**
     * 文件导出下载到浏览器客户端
     *
     * @param response       输出流
     * @param fileName       下载到的文件名称
     * @param data           需要导出的数据集合, 如果为空，则下载到空表格
     * @param excelExportSet 表头列名映射
     */
    public static void export(HttpServletResponse response, String fileName, List data,
                              ExcelExportSet excelExportSet) {
        try {
            String downloadFileName = genFileName(fileName);
            OutputStream downloadStream = WebUtils.getDownloadStream(response, downloadFileName);
            export(downloadStream, data, excelExportSet);
        } catch (IOException e) {
            log.error("导出数据异常", e);
            ExceptionThrowUtils.of("导出数据异常");
        }
    }

    /**
     * 导出的文件夹
     *
     * @param fileDir        文件夹路径
     * @param data           数据集合
     * @param excelExportSet 表头列名映射
     */
    public static void export(String fileDir, List data,
                              ExcelExportSet excelExportSet) {
        try {
            String downloadFileName = genFileNameByDate();
            FileOutputStream fileOutputStream = new FileOutputStream(fileDir + "/" + downloadFileName);
            export(fileOutputStream, data, excelExportSet);
        } catch (IOException e) {
            log.error("导出数据异常", e);
            ExceptionThrowUtils.of("导出数据异常");
        }
    }

    /**
     * 导出的文件夹
     *
     * @param fileDir        文件夹路径
     * @param fileName       文件名称
     * @param data           数据集合
     * @param excelExportSet 表头列名映射
     */
    public static void export(String fileDir, String fileName, List data,
                              ExcelExportSet excelExportSet) {
        try {
            String downloadFileName = genFileName(fileName);
            FileOutputStream fileOutputStream = new FileOutputStream(fileDir + "/" + downloadFileName);
            export(fileOutputStream, data, excelExportSet);
        } catch (IOException e) {
            log.error("导出数据异常", e);
            ExceptionThrowUtils.of("导出数据异常");
        }
    }

    /**
     * 导出
     *
     * @param downloadStream 输出流
     * @param data           数据集合
     * @param excelExportSet 表头列名映射
     */
    public static void export(OutputStream downloadStream, List data,
                              ExcelExportSet excelExportSet) {
        if (Objects.isNull(data)) {
            data = new ArrayList<>(0);
        }
        boolean isWriteKeyAsHead = false;
        ExcelWriter writer = ExcelUtil.getWriter();
        if (Objects.nonNull(excelExportSet)) {
            // 设置名称
            if (StrUtil.isNotBlank(excelExportSet.getSheetName())) {
                writer.renameSheet(excelExportSet.getSheetName());
            }
            isWriteKeyAsHead = CollectionUtil.isNotEmpty(excelExportSet.getHeaderAlias());
            if (isWriteKeyAsHead) {
                // 自定义表头
                writer.setHeaderAlias(excelExportSet.getHeaderAlias());
                writer.setOnlyAlias(true);
            }
        }
        // 宽度自适应
        writer.autoSizeColumnAll();
        // 进行转换转换
        List<Map<String, Object>> dataMap = convert(data, excelExportSet);
        // 写入数据
        writer.write(dataMap, isWriteKeyAsHead);
        writer.flush(downloadStream, true);
    }

    public static String genFileName() {
        return genFileName(null);
    }

    public static String genFileName(String fileName) {
        if (StrUtil.isBlank(fileName)) {
            return IdUtil.fastSimpleUUID() + DEFAULT_SUFFIX;
        }
        if (fileName.endsWith(".xlsx") || fileName.endsWith(".xls")) {
            return fileName;
        }
        return fileName + DEFAULT_SUFFIX;
    }

    public static String genFileNameByDate() {
        return genFileNameByDate(null);
    }

    public static String genFileNameByDate(String fileNamePrefix) {
        StringBuilder stringBuilder = new StringBuilder();
        if (StrUtil.isNotBlank(fileNamePrefix)) {
            stringBuilder.append(fileNamePrefix);
            if (!fileNamePrefix.endsWith("_")) {
                stringBuilder.append("_");
            }
        }
        String dateFormat = DateUtil.date().toString(PURE_DATETIME_FORMAT);
        stringBuilder.append(dateFormat);
        stringBuilder.append(DEFAULT_SUFFIX);
        return stringBuilder.toString();
    }


    /**
     * 将数据集合进行转换
     *
     * @param data           需要导出的数据集合
     * @param excelExportSet 表头以及列转换
     * @return 生成的表格数据集合
     */
    public static List<Map<String, Object>> convert(List data, ExcelExportSet excelExportSet) {
        if (CollectionUtil.isEmpty(data)) {
            return new ArrayList<>();
        }
        List<Map<String, Object>> result = new ArrayList<>(data.size());
        boolean hansFieldValueFunction = Objects.nonNull(excelExportSet) && CollectionUtil.isNotEmpty(excelExportSet.getFieldValueFunctionMap());
        for (Object datum : data) {
            Map<String, Object> stringObjectMap = BeanUtil.beanToMap(datum);
            if (hansFieldValueFunction) {
                excelExportSet.getFieldValueFunctionMap().forEach((key, function) -> {
                    Object value = stringObjectMap.get(key);
                    Object apply = function.apply(value);
                    stringObjectMap.put(key, apply);
                });
            }
            result.add(stringObjectMap);
        }
        return result;
    }

    /* 实例代码
    public static void main(String[] args) {
        ExcelExportSet excelExportSet = ExcelExportSet.of("用户信息")
                .addHeaderAlias("img", "头像链接")
                .addHeaderAlias("phone", "手机号")
                .addHeaderAlias("name", "名称")
                .addHeaderAlias("age", "年龄")
                .addFieldAliasAndValueFunction("gender", "性别", value -> BaseEnum.getDescByCode(GenderEnum.class, (String) value));

        List<UserTest> userTests = new ArrayList<>();
        UserTest userTest = new ExcelUtils.UserTest("张三1", "https://s1.ax1x.com/2023/08/23/pPJXDVe.png", "18888888888", 18, "1");
        userTests.add(userTest);

        userTest = new ExcelUtils.UserTest("张三2", "https://s1.ax1x.com/2023/08/23/pPJXDVe.png", "18888888888", 18, "2");
        userTests.add(userTest);

        userTest = new ExcelUtils.UserTest("张三3", "https://s1.ax1x.com/2023/08/23/pPJXDVe.png", "18888888888", 18, "3");
        userTests.add(userTest);

        List<Map<String, Object>> convert = convert(userTests, excelExportSet);
        System.out.println(convert);

        long l = System.currentTimeMillis();
        ExcelUtils.export("/Users/dazhou/Desktop/大周的文件", userTests, excelExportSet);
        long cast = System.currentTimeMillis() - l;
        System.out.println("总列数：" + excelExportSet.getHeaderAlias().size() + ", 总行数：" + userTests.size() + ",总耗时(毫秒)：" + cast);

    }

    @Data
    @AllArgsConstructor
    static class UserTest {

        private String name;
        private String img;
        private String phone;
        private Integer age;
        private String gender;

    }*/


}
